package coreModel;

import hitExceptions.InvalidOperationException;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Collection;

import dataPersistence.DB_DAOFactory;
import dataPersistence.DataPersistenceFactory;
import dataPersistence.Serial_DAOFactory;
import dataPersistence.Serializer;
import dataPersistence.TransactionManager;

/**
 *This class uses the Singleton design pattern to control the action history, storage units, and 
 *removed items 
 * @author The Fantastic 4
 *
 */
public class HIT extends SerializableImplementer{

	private History programHistory;
	private static HIT hitInstance;
	private DataPersistenceFactory factory;
	private boolean loadingFromDataBase;


	/**
	 * @return the loadingFromDataBase
	 */
	public boolean isLoadingFromDataBase()
	{
		return loadingFromDataBase;
	}

	/**
	 * @param loadingFromDataBase the loadingFromDataBase to set
	 */
	public void setLoadingFromDataBase(boolean loadingFromDataBase)
	{
		this.loadingFromDataBase = loadingFromDataBase;
	}

	//this is the default file location
	private String fileLocation;

	//Managers
	private StorageUnitManager storageManager;
	private ItemManager itemManager;
	private ProductManager productManager;



	private Serializer serializer;
	private RemovedItemManager itemHistory;


	/**
	 * HIT constructor, Constructs a storage unit
	 * Defaults to a Serail_DAOFactory
	 */
	private HIT()
	{
		//set storage units
		fileLocation="hit.db";
		serializer= new Serializer(fileLocation);
		//init managers
		productManager= new ProductManager();
		itemManager= new ItemManager();
		storageManager = new StorageUnitManager();
		itemHistory= new RemovedItemManager();

		//added for db usage
		TransactionManager.initialize();
		
		factory = new Serial_DAOFactory();
		loadingFromDataBase=false;
	}

	/**
	 * @return the factory
	 */
	public DataPersistenceFactory getFactory() {
		return factory;
	}
	
	
	public void setDataPersistenceFactory(boolean isDB)
	{
		if (isDB)
			factory = new DB_DAOFactory();
		else
			factory = new Serial_DAOFactory();
	}
	
	/**
	 * 
	 * @return a RemovedItems object containing the history
	 */
	public RemovedItemManager getItemHistory() 
	{
		return itemHistory;
	}


	/**
	 * Returns the HIT instance, if one is already created it returns that one if there is 
	 * not a HIT created it creates one and returns it.
	 * 
	 * @return The HIT instance
	 * 
	 */
	public static HIT getInstance()
	{
		if(hitInstance==null)
		{
			hitInstance=new HIT();
			return hitInstance;
		}
		else
			return hitInstance;

	}

	/**
	 * Returns product manager.
	 * 
	 * @return The product manager
	 * 
	 */
	public  ProductManager getProductManager() 
	{
		return productManager;
	}

	/**
	 * Returns item manager.
	 * 
	 * @return The item manager
	 * 
	 */

	public  ItemManager getItemManager() 
	{
		return itemManager;
	}

	/**
	 * Returns storage unit mana// TODO Auto-generated method stubger.
	 * 
	 * @return The storage unit manager
	 * 
	 */

	public  StorageUnitManager getStorageUnitManager() 
	{
		return storageManager;
	}


	/**
	 * This function is to be able to load object from a serialized data source and be able to 
	 * place it inside the HIT class
	 * @param instance HIT object
	 */
	public static void setInstance(HIT instance)
	{
		hitInstance=instance;
	}

	/**
	 * Checks the name against currently named storage units, returns true if name is unique
	 *  
	 * @param name name that the new storage unit will be called
	 * @return boolean, true iff name is not a current storage unit
	 */
	public boolean canAddStorageUnit(StorageUnit unit)
	{
		if(storageManager.containsStorageUnit(unit)) 
			return false;
		else
			return true;
	}

	/**
	 * Loads the serialized HIT object into it's data structure
	 * 
	 * @param file The file to load from
	 * @throws InvalidOperationException 
	 * @throws FileNotFoundException When file is not located
	 */
	public void load(String file) throws InvalidOperationException 
	{
		//serializer.loadObjects(file);
		//changed to factory load
		factory.load(file);
	}

	/**
	 * Loads the default serialized HIT object into it's 		System.out.println("in db load");data structure, if one is not created it 
	 * creates the file and returns
	 * 
	 */
	public void load() 
	{

		try
		{
			//serializer.loadObjects();
			//changed to factory
			factory.load();
		} 
		catch (InvalidOperationException e)
		{

			e.printStackTrace();
		}
	}

	/**
	 * Saves a serialized hit object to the specified file.
	 * 
	 * @param file Where to save the serialized HIT object to
	 * @throws IOException when save can not be completed
	 * @throws InvalidOperationException 
	 */
	public void save(String file) throws InvalidOperationException
	{
		//serializer.saveObjects(this, file);
		factory.save(file);
	}

	/**
	 * Saves a serialized hit object to the default file.
	 */
	public void save()
	{

		try
		{
			//serializer.saveObjects(this);
			factory.save();
		} 
		catch (InvalidOperationException e)
		{
			System.err.println(e.getMessage());
		}
	}

	//	/**
	//	 * Imports an xml file and converts it's data into the HIT data structure
	//	 * 
	//	 * @param fileLocation location of the file to import
	//	 * @throws FileNotFoundException
	//	 * @throws IOException
	//	 */
	//	public void importXML(String fileLocation) throws FileNotFoundException, IOException
	//	{
	//		
	//	}

	//	/**
	//	 * Converts the HIT data structure into and XML data structure and exports the xml to the 
	//	 *file specified
	//	 * @param fileLocation
	//	 * @throws FileNotFoundException
	//	 * @throws IOException
	//	 */
	//	public void exportXML(String fileLocation) throws FileNotFoundException, IOException
	//	{
	//		
	//	}

	/**
	 * Adds a storage unit to the HIT, throws an exception if that storage unit is already in
the list of storage units. Use canAddStorageUnit() to check if a name is already used.
	 * @param unitName Name of the storage unit to add
	 * @throws InvalidOperationException 
	 */
	public void addStorageUnit(StorageUnit unit) throws InvalidOperationException
	{
		storageManager.addStorageUnit(unit, true);
	}

	/**
	 * Removes an empty storage unit from the list of storage units, use isEmpty() call on the
	 *  storage unit to check if it is empty
	 * @param unitName name of storage unit to delete
	 * @throws UnsupportedOperationException thrown when the storage unit is not empty
	 */
	public void removeStorageUnit(StorageUnit unit) throws UnsupportedOperationException
	{
		storageManager.removeStorageUnit(unit);
	}

	/**
	 * Checks to see if a storage unit can be removed.
	 * @param unit the storageUnit that wants to be removed
	 * @return true iff the unit is empty of all items
	 */
	public boolean canRemoveStorageUnit(StorageUnit unit)
	{
		return storageManager.canRemoveStorageUnit(unit);
	}

	/**
	 * Return the storageUnit object that corresponds to the unitName
	 * @param unitName name of storage unit
	 * @return the storage unit that corresponds to that name
	 */
	public StorageUnit getStorageUnit(String unitName)
	{
		return storageManager.getStorageUnit(unitName);
	}

	/**
	 * Returns a collections of all the storage units
	 * @return a collections containing all the storageUnits
	 */
	public Collection<StorageUnit> getAllStorageUnits()
	{
		return storageManager.getStorageUnits();
	}

	/**
	 * @return the serializer
	 */
	public Serializer getSerializer()
	{
		return serializer;
	}
	
}
